package algorithms.que13;

import edu.princeton.cs.algs4.StdRandom;

import java.util.Iterator;
import java.util.Random;

/**
 * @功能
 * @创建时间 2020/7/12
 */
public class RandomQueue1<Item>  implements Iterable<Item>{
    private Item[] array;
    private int N;


    private void resize(int max){
        Item[] temp = (Item[]) new Object[max];
        for (int i = 0; i < N; i++) {
            temp[i] = array[i];
        }
        array = temp;
    }

    public RandomQueue1() {
        array = (Item[]) new Object[1];
        N = 0;
    }
    public boolean isEmpty() {
        return N==0;
    }

    public void enqueue(Item item){
        if(N == array.length) {
            resize(2*N);
        }
        array[N++] = item;
    }

    //随机返回一个元素 并删除
    public Item dequeue() {
        if(N==0){
            System.out.println("队列已空");
            return null;
        }
        Random random = new Random();
        int index = random.nextInt(N);//返回0到N-1之间的一个随机整数
        //交换array[N-1]和array[index]的值
        Item temp = array[N-1];
        array[N-1] = array[index];
        array[index] = temp;
        temp = array[--N];
        array[N] = null;//置空，避免对象游离
        if(N>0 && N == array.length/4)
            resize(array.length/2);
        return temp;
    }

    //随机返回一个元素但是不删除
    public Item sample() {
        if(N==0){
            System.out.println("队列已空");
            return null;
        }
        Random random = new Random();
        int index = random.nextInt(N);//返回0到N-1之间的一个随机整数
        return array[index];
    }

    @Override
    public Iterator<Item> iterator() {
        return new  RandomQueueIterator();
    }

    private class RandomQueueIterator implements Iterator {

        //使用一个数组记录打乱的下标，以打乱的下标去访问原数组，实现快速随机访问
        private int[] seq = new int[N];
        private int index = 0;
        public RandomQueueIterator() {
            for(int i=0;i<N;i++) {
                seq[i] =i;
            }
            StdRandom.shuffle(seq);
            /*
            此函数的源码如下：
            public static void shuffle(int[] a) {
                validateNotNull(a);
                int n = a.length;
                //此函数遍历数组，使每一个元素都随机和另一个交换为位置
                //此方法何以保证每个新的迭代器得到N!种排列出现的可能性相等
                for (int i = 0; i < n; i++) {
                    int r = i + uniform(n-i);     // between i and n-1
                    int temp = a[i];
                    a[i] = a[r];
                    a[r] = temp;
                }
            }
            //返回0-n之间的随机一个正整数
            public static int uniform(int n) {
                if (n <= 0) throw new IllegalArgumentException("argument must be positive: " + n);
                return random.nextInt(n);
            }
             */
        }
        @Override
        public boolean hasNext() {
            return index<N;
        }

        @Override
        public Object next() {
            return array[seq[index++]];
        }
    }
}


